package com.taa.service.impl;

import com.taa.dao.IOrderInfoDao;
import com.taa.dao.IOrderItemDao;
import com.taa.dao.po.DishInfo;
import com.taa.dao.po.OrderInfo;
import com.taa.dao.po.OrderItem;
import com.taa.dto.DishStockDTO;
import com.taa.dto.OrderCreateDTO;
import com.taa.dto.OrderDetailDTO;
import com.taa.dto.OrderSubmitDTO;
import com.taa.enums.ResponseCode;
import com.taa.exception.AppException;
import com.taa.feign.RestaurantFeignClient;
import com.taa.response.Response;
import com.taa.service.IOrderService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * @Author: taa
 * @Desc: 订单服务实现类
 * @Create: 2025-06-22 17:36
 **/
@Slf4j
@Service
public class OrderServiceImpl implements IOrderService {

    @Resource
    private IOrderInfoDao orderInfoDao;
    @Resource
    private IOrderItemDao orderItemDao;
    @Resource
    private RestaurantFeignClient restaurantFeignClient;

    @Override
    @Transactional
    public OrderSubmitDTO createOrder(OrderCreateDTO createOrderDTO, Long userId) {
        // 1. 通过Feign Client批量获取菜品信息
        List<Long> dishIds = createOrderDTO.getItems().stream()
                .map(OrderCreateDTO.OrderItemCreateDTO::getDishId).collect(Collectors.toList());

        Response<List<DishInfo>> dishListResponse = restaurantFeignClient.getDishListByIds(dishIds);
        if (!Objects.equals(dishListResponse.getCode(), ResponseCode.SUCCESS.getCode())) {
            throw new AppException(dishListResponse.getCode(), "获取菜品信息失败: " + dishListResponse.getInfo());
        }
        List<DishInfo> dishInfos = dishListResponse.getData();
        Map<Long, DishInfo> dishInfoMap = dishInfos.stream()
                .collect(Collectors.toMap(DishInfo::getId, dish -> dish));

        // 2. 校验库存并计算总价
        BigDecimal totalAmount = BigDecimal.ZERO;
        for (OrderCreateDTO.OrderItemCreateDTO itemDTO : createOrderDTO.getItems()) {
            DishInfo dishInfo = dishInfoMap.get(itemDTO.getDishId());
            if (dishInfo == null) {
                throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), "菜品不存在, ID: " + itemDTO.getDishId());
            }
            if (dishInfo.getStock() < itemDTO.getQuantity()) {
                throw new AppException(ResponseCode.STOCK_NOT_ENOUGH.getCode(), "菜品[" + dishInfo.getName() + "]库存不足");
            }
            totalAmount = totalAmount.add(dishInfo.getPrice().multiply(new BigDecimal(itemDTO.getQuantity())));
        }

        // 3. 创建订单主表记录
        OrderInfo orderInfo = new OrderInfo();
        String orderNo = UUID.randomUUID().toString().replace("-", "");
        orderInfo.setOrderNo(orderNo);
        orderInfo.setUserId(userId);
        orderInfo.setRestaurantId(createOrderDTO.getRestaurantId());
        orderInfo.setTotalAmount(totalAmount);
        orderInfo.setStatus(0); // 0:待支付
        orderInfoDao.insert(orderInfo);

        // 4. 创建订单明细列表
        List<OrderItem> orderItems = createOrderDTO.getItems().stream().map(itemDTO -> {
            DishInfo dishInfo = dishInfoMap.get(itemDTO.getDishId());
            OrderItem orderItem = new OrderItem();
            orderItem.setOrderNo(orderNo);
            orderItem.setDishId(itemDTO.getDishId());
            orderItem.setDishName(dishInfo.getName());
            orderItem.setDishPrice(dishInfo.getPrice());
            orderItem.setQuantity(itemDTO.getQuantity());
            return orderItem;
        }).collect(Collectors.toList());
        orderItemDao.batchInsert(orderItems);

        // 5. 通过Feign Client批量扣减库存
        List<DishStockDTO> dishStockList = createOrderDTO.getItems().stream().map(itemDTO -> {
            DishStockDTO stockDTO = new DishStockDTO();
            stockDTO.setDishId(itemDTO.getDishId());
            stockDTO.setQuantity(itemDTO.getQuantity());
            return stockDTO;
        }).collect(Collectors.toList());
        Response<Void> decreaseStockResponse = restaurantFeignClient.decreaseStock(dishStockList);
        if (!Objects.equals(decreaseStockResponse.getCode(), ResponseCode.SUCCESS.getCode())) {
            throw new AppException(decreaseStockResponse.getCode(), "扣减库存失败: " + decreaseStockResponse.getInfo());
        }

        // 6. 构建并返回响应DTO
        return OrderSubmitDTO.builder()
                .orderNo(orderNo)
                .build();
    }

    @Override
    public OrderDetailDTO getOrderDetailByOrderNo(String orderNo, Long userId) {
        // 1. 查询订单主信息
        OrderInfo orderInfo = orderInfoDao.findByOrderNo(orderNo);
        if (orderInfo == null) {
            throw new AppException(ResponseCode.ORDER_NOT_FOUND.getCode(), ResponseCode.ORDER_NOT_FOUND.getInfo());
        }

        // 2. 权限校验
        if (!orderInfo.getUserId().equals(userId)) {
            throw new AppException(ResponseCode.ORDER_NOT_FOUND.getCode(), ResponseCode.ORDER_NOT_FOUND.getInfo());
        }

        // 3. 查询订单明细信息
        List<OrderItem> orderItems = orderItemDao.findByOrderNo(orderNo);

        // 4. 将订单明细PO列表转换为DTO列表
        List<OrderDetailDTO.OrderItemDetailDTO> itemDTOs = orderItems.stream().map(item ->
                OrderDetailDTO.OrderItemDetailDTO.builder()
                        .dishName(item.getDishName())
                        .dishPrice(item.getDishPrice())
                        .quantity(item.getQuantity())
                        .build()
        ).collect(Collectors.toList());

        // 5. 组装并返回订单详情DTO
        return OrderDetailDTO.builder()
                .orderNo(orderInfo.getOrderNo())
                .totalAmount(orderInfo.getTotalAmount())
                .status(orderInfo.getStatus())
                .createTime(orderInfo.getCreateTime())
                .items(itemDTOs)
                .build();
    }

    @Override
    public void updateOrderStatus(String orderNo, Integer status) {
        int result = orderInfoDao.updateStatusByOrderNo(orderNo, status);
        if (result <= 0) {
            // 记录日志，但在服务间调用中，通常由调用方处理异常
            log.error("更新订单状态失败, orderNo: {}, status: {}", orderNo, status);
            throw new AppException(ResponseCode.ORDER_STATUS_UPDATE_FAILED.getCode(), ResponseCode.ORDER_STATUS_UPDATE_FAILED.getInfo());
        }
        log.info("订单状态更新成功, orderNo: {}, status: {}", orderNo, status);
    }

}

